// addrspace.cc 
//	Routines to manage address spaces (executing user programs).
//
//	In order to run a user program, you must:
//
//	1. link with the -N -T 0 option 
//	2. run coff2noff to convert the object file to Nachos format
//		(Nachos object code format is essentially just a simpler
//		version of the UNIX executable object code format)
//	3. load the NOFF file into the Nachos file system
//		(if you haven't implemented the file system yet, you
//		don't need to do this last step)
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "system.h"
#include "addrspace.h"
#include "noff.h"
#include "table.h"
#include "synch.h"

#define InvalidFlag -1;		//OceanMaster, -1 is corresponding to Max Unsign int, so make it the default Invalid flag

extern "C" { int bzero(char *, int); };

Table::Table(int s) : map(s), table(0), lock(0), size(s) {
    table = new void *[size];
    lock = new Lock("TableLock");
}

Table::~Table() {
    if (table) {
	delete table;
	table = 0;
    }
    if (lock) {
	delete lock;
	lock = 0;
    }
}

void *Table::Get(int i) {
    // Return the element associated with the given if, or 0 if
    // there is none.

    return (i >=0 && i < size && map.Test(i)) ? table[i] : 0;
}

int Table::Put(void *f) {
    // Put the element in the table and return the slot it used.  Use a
    // lock so 2 files don't get the same space.
    int i;	// to find the next slot

    lock->Acquire();
    i = map.Find();
    lock->Release();
    if ( i != -1)
	table[i] = f;
    return i;
}

void *Table::Remove(int i) {
    // Remove the element associated with identifier i from the table,
    // and return it.

    void *f =0;

    if ( i >= 0 && i < size ) {
	lock->Acquire();
	if ( map.Test(i) ) {
	    map.Clear(i);
	    f = table[i];
	    table[i] = 0;
	}
	lock->Release();
    }
    return f;
}

//----------------------------------------------------------------------
// SwapHeader
// 	Do little endian to big endian conversion on the bytes in the 
//	object file header, in case the file was generated on a little
//	endian machine, and we're now running on a big endian machine.
//----------------------------------------------------------------------

static void 
SwapHeader (NoffHeader *noffH)
{
	noffH->noffMagic = WordToHost(noffH->noffMagic);
	noffH->code.size = WordToHost(noffH->code.size);
	noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
	noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
	noffH->initData.size = WordToHost(noffH->initData.size);
	noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
	noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
	noffH->uninitData.size = WordToHost(noffH->uninitData.size);
	noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
	noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
}

//----------------Project 3------------------
#ifdef USE_TLB
int AddrSpace::OnMissIPT(int vpn)
{	//On IPT MISS

	DEBUG('%',"[Miss IPT] Querying VPN=%d \n",vpn);
	//Step3: Still assume we have unlimited memory,
	//	Only reason a IPT Miss is that it is not initialized.
	//TODO: On Step4, will have to consider eviction

	//1)allocate memory
	int phys;
	//2)update pagetable and memory data

	//BUG!! should move this codes to AddrSapce, and protected with PageTableLock!!!!
	/*
	if(myExecutable == NULL)
	{
		printf("FATAL ERROR : Executable File(Runtime) is NULL\n");
		return -1;
	}*/
	pageTableLock -> Acquire();

	if(pageTable[vpn].valid)		//if it is valid, should have been initialized
	{
		printf("FATAL ERROR : Calling On IPT Miss while the page is in memory.");	
	}
	else					//maybe not initialized, initialize.
	{
		phys = RequestMemoryPage();

		if(phys == -1)
		{
			//Physical memory is full!!!
			// Do eviction!!!
			DEBUG('4',"[Miss IPT] Physical Memory not enough, call evict\n");
			IntStatus oldLevel = interrupt -> SetLevel(IntOff);
			phys = evictIPT();
			interrupt -> SetLevel(oldLevel);
		}

		pageTable[vpn].valid = true;			//from now on, it is within VirtualSpace, until it is released and marked invalid.
		pageTable[vpn].physicalPage = phys;
		
		DEBUG('2',"Allocating - Virtual P#%03d Addr: 0x%06x Physical P#%03d Addr 0x%06x size %u \n", vpn, vpn*PageSize, phys, phys*PageSize, PageSize);
	
		if(pageTable[vpn].inDisk)				//if it is in disk, restore from disk
		{
			DEBUG('4',"[Miss IPT] Restore data from disk\n");
			ReadFromSwap(phys, pageTable[vpn].posId);
			pageTable[vpn].inDisk = false;
			pageTable[vpn].posId = -1;
		}
		else									//else, init data
		{
			DEBUG('4',"[Miss IPT] Init data from executable\n");
			
			if(pageTable[vpn].posId!=-1)
				printf("FATAL ERROR : posId != -1, but recognized as not in disk\n");

			if(vpn == (CISegPages - 1 ) )	//this page is last page in Code&InitData section
			{
				DEBUG('$',"This Is Tail of CI Segments!!!\n");
				DEBUG('$',"Copying from file %5d to memory P#%03d Addr 0x%06x , Size %u \n", CopyStartAddrInFile + vpn * PageSize , phys, pageTable[vpn].physicalPage * PageSize , TailSize);
				bzero( machine->mainMemory+phys*PageSize,PageSize);
				myExecutable -> ReadAt(&(machine->mainMemory[ phys*PageSize]), TailSize, CopyStartAddrInFile + vpn * PageSize);
			}
			else if (vpn < CISegPages)	//this page is in Code or InitData
			{
				DEBUG('$',"Copying from file %5d to memory P#%03d Addr 0x%06x , Size %u \n", CopyStartAddrInFile + vpn * PageSize , phys, pageTable[vpn].physicalPage * PageSize , PageSize);
				myExecutable -> ReadAt(&(machine->mainMemory[ phys*PageSize]), PageSize, CopyStartAddrInFile + vpn * PageSize);
			}
			else
			{
				bzero(machine -> mainMemory + phys*PageSize, PageSize);
			}
		}
	}
	DEBUG('4',"[Miss IPT] SUCCESS  VPN=%-3d PPN=%-3d valid=%d inDisk=%d\n", vpn, phys, pageTable[vpn].valid, pageTable[vpn].inDisk);
			
	//3)poplate IPt
	populateIPT(vpn,phys,true, pageTable[vpn].use, pageTable[vpn].dirty, pageTable[vpn].readOnly);
	//4)return, aotumatically update TLB
	pageTableLock -> Release();
	return phys;
}
//------------------Add end-------------------
#endif

//----------------------------------------------------------------------
// AddrSpace::AddrSpace
// 	Create an address space to run a user program.
//	Load the program from a file "executable", and set everything
//	up so that we can start executing user instructions.
//
//	Assumes that the object code file is in NOFF format.
//
//	"executable" is the file containing the object code to load into memory
//
//      It's possible to fail to fully construct the address space for
//      several reasons, including being unable to allocate memory,
//      and being unable to read key parts of the executable.
//      Incompletely consretucted address spaces have the member
//      constructed set to false.
//----------------------------------------------------------------------


//-----------------Project 2------------------
// Modified Constructor
//	1)change to MultiProcess
//	2)copy in pages
//	by OceanMaster
//--------------------------------------------

AddrSpace::AddrSpace(OpenFile *executable) : fileTable(MaxOpenFiles) 
{
    NoffHeader noffH;
    unsigned int i, size;

	//-----------------project 2------------------
	//Modified by OceanMaster
	//Step0: init varible;
	
	//nextThreadId = 1;	//0 is current thread, next thread will take 1
	nextStackId = 0;	//next StackId to be assigned	
	userStackNum = 2;	//number of user stacks allocated at first time
	//threadTable = new Thread*[1];
	//threadTable[0] = currentThread;	//first Thread is current Thread...!!!!!!!!Still need to investigate!!!!!!

	pageTableLock = new Lock("PageTableLock");
	//threadTableLock = new Lock("ThreadTableLock");
	//--------------------------------------------

    // Don't allocate the input or output to disk files
    fileTable.Put(0);
    fileTable.Put(0);

    executable->ReadAt((char *)&noffH, sizeof(noffH), 0);					//OceanMaster: Read header from executable
    if ((noffH.noffMagic != NOFFMAGIC) && 
		(WordToHost(noffH.noffMagic) == NOFFMAGIC))
    	SwapHeader(&noffH);
    ASSERT(noffH.noffMagic == NOFFMAGIC);

	// size = noffH.uninitData.virtualAddr + noffH.uninitData.size ;			
	size = noffH.code.size + noffH.initData.size + noffH.uninitData.size;
   
	//OceanMaster: Count total size of Code + init Data + Uninit Data
    // Changed From size + size + size TO uninitData.virtualAddr + uninitData.size
    // In case there is blank between segments.
    
	//--------------------project 2-------------------
	RootStackPage =	 divRoundUp(size, PageSize);						//OceanMaster: Remember where user stacks pages starts, in V addr
	codeSize = noffH.code.size;

	//---------------------Add end--------------------

	numPages = divRoundUp(size, PageSize) + userStackNum * NumStackPages;			//OceanMaster: Count total pages needed by size and stack size
					//+ divRoundUp(UserStackSize,PageSize);										
    
	DEBUG('2', "Address Space Request Memory: NumPages [%d] = [%d] for Code/Data + [%d] for [%d] stacks, Total Size [%d]\n",numPages, divRoundUp(size, PageSize), userStackNum * NumStackPages, userStackNum, numPages * PageSize);

#ifndef USE_TLB		//Without USE_TLB, Project2 code remains

	size = numPages * PageSize;														//OceanMaster: Recount total size by make full frame

    //ASSERT(numPages <= NumPhysPages);		
						// check we're not trying
						// to run anything too big --
						// at least until we have
						// virtual memory

    DEBUG('a', "Initializing address space, num pages %d, size %d\n",numPages, size);


	//---------------------Project 2-------------------
	//Modified by OceanMaster
	//Step1: set up the address translation 
    
	pageTable = new TranslationEntry[numPages];

	for (i = 0; i < numPages; i++) 
	{
		int physPage = RequestMemoryPage();
		if(physPage == -1)
		{
			printf("FATAL ERROR: Memory not enough to assign new page!!!!\n");
			return;//TO DO MORE
		}


		pageTable[i].virtualPage = i;
		pageTable[i].physicalPage = physPage;								//Project2:	allocate physical address to virtual page
		pageTable[i].valid = TRUE;
		pageTable[i].use = FALSE;
		pageTable[i].dirty = FALSE;

		if( ((i+1)*PageSize) <= (unsigned int)noffH.code.size)				//Project2:	if whole page is code segment, set readonly
			pageTable[i].readOnly = TRUE;
		else
			pageTable[i].readOnly = FALSE;  
		// if the code segment was entirely on a separate page, we could set its pages to be read-only

		// zero out the entire address space, to zero the unitialized data segment	//Project2: zero out assigned page
		// and the stack segment
		
		DEBUG('2',"Allocating - Virtual P#%03d Addr: 0x%06x Physical P#%3d Addr 0x%06x size %u \n", i, i*PageSize, physPage, physPage*PageSize, PageSize);
		
		bzero( machine->mainMemory+physPage*PageSize,PageSize);		//This is a UNIX function, our Main Memory is also regarded as a offset in it
	}
	
	DEBUG('2',"Copying CODE segment and DATA segment \n");

	//Step2: copy code and data segments into memory
    //size = noffH.initData.virtualAddr + noffH.initData.size;		//In case there is blank between segments
	size = noffH.code.size + noffH.initData.size;
	
	i=0;

	//	2-1: Copy in Pages
	//	Potential Buggy:
	//	How segments arrangement varis between in file and in virtual address?
	//	Solved, Crowley says code segment and initData segment relies no blank between them

	while(size>PageSize)
	{
		DEBUG('2',"Copying from file %5d to memory P#%03d Addr 0x%06x , Size %u ,Size Remaining to copy %u \n", noffH.code.inFileAddr + i*PageSize, pageTable[i].physicalPage, pageTable[i].physicalPage * PageSize , PageSize, size - PageSize);
		
		executable->ReadAt(&(machine->mainMemory[ pageTable[i].physicalPage * PageSize ]),
			PageSize, noffH.code.inFileAddr + i*PageSize);
		
		size -= PageSize;
		i++;
	}
	//	2-2: Copy last part
	DEBUG('2',"Copying from file %5d to memory P#%03d Addr 0x%06x , Size %u \n",noffH.code.inFileAddr + i*PageSize, pageTable[i].physicalPage, pageTable[i].physicalPage * PageSize , size);
	executable->ReadAt(&(machine->mainMemory[ pageTable[i].physicalPage * PageSize ]),
			size, noffH.code.inFileAddr + i*PageSize);

#else			//USE_TLB, Project3 added

	size = noffH.code.size + noffH.initData.size;
	DEBUG('$',"===============================\n");
	DEBUG('$',"Segments Size:\n");
	DEBUG('$',"	Code:%d\n	InitData:%d\n	UninitData:%d\n	PageSize:%d\n",noffH.code.size,noffH.initData.size,noffH.uninitData.size,PageSize);
	DEBUG('$',"	Code.size + initData.size = %d\n",size);
	DEBUG('$',"===============================\n");

	pageTable = new OnDemandTranslationEntry[numPages];
	myExecutable = executable;	//store executable file.
	CopyStartAddrInFile = noffH.code.inFileAddr;
	CISegPages = divRoundUp(size, PageSize);
	TailSize = size % PageSize;
	if(TailSize==0)
		TailSize = PageSize;
			
	DEBUG('$',"===============================\n");
	DEBUG('$',"Executable File Examined:\n");
	DEBUG('$',"	numPages=%3d\n	CopystartAddr=%3d\n	CISegPages=%3d\n	TailSize=%3d\n", numPages, CopyStartAddrInFile, CISegPages, TailSize);
	DEBUG('$',"===============================\n");
	
	//--------------------Project3---------------------------
	//Modified by OceanMaster

	//Initialize Page Table
	for (i = 0; i < numPages; i++) 
	{
		bool readOnly = false;
		if( ((i+1)*PageSize) <= (unsigned int)noffH.code.size)				//if whole page is code segment, set readonly
			readOnly = true;
	
		pageTable[i].virtualPage = i;
		pageTable[i].valid = false;											//Project3: every page is invalid at very beginning
		pageTable[i].use = false;
		pageTable[i].dirty = false;
		pageTable[i].readOnly = readOnly;
		pageTable[i].inDisk = false;										//Project3: if this page is in disk
		pageTable[i].posId = -1;
	}

#endif			//USE_TLB	
}

//-------------------------------Project 2------------------------------
// New Functions:
//	1) AllocateStackId()
//	2) RecycleStackId(int)
//	2) GetStackVaddr(int)
//	by OceanMaster
//----------------------------------------------------------------------

//Assumption: return -1 if error occured;
//Using: 	nextStackId
//		userStackNum
//May use:
//		pageTable
//		numPages
int AddrSpace::AllocateStackId()
{
#ifndef USE_TLB		//Without TLB, project2 code remains
	int StackId;
	pageTableLock -> Acquire();
	
	//Step1: Allocate Stack
	//1-1:	Assign StackId
	StackId = nextStackId;
	nextStackId ++;

	DEBUG('2',"Allocate New Stack Id [%d] \n", StackId);	

	//1-2: If Memory isn't enough, ask OS for more
	if(StackId == userStackNum)	
	{	
		int AddStackNum = userStackNum;	//Every time reach stack bound, double current stacks num
		int AddPageNum = AddStackNum * NumStackPages;
	
		DEBUG('2',"Memory Not Enough, Allocating new Memory, Num Pages [%d] Size [%d] \n", AddPageNum, AddPageNum * PageSize);	
		
		TranslationEntry * newPageTable = new TranslationEntry[numPages+AddPageNum];
		TranslationEntry * oldPageTable = pageTable;
	
		for(int i=0; i<numPages; i++)		//Copy old memory page translation entries
		{
			newPageTable[i] = oldPageTable[i];
		}
		
		for(int i=numPages;i<numPages+AddPageNum;i++)//Allocate new memory pages
		{
			int physPage = RequestMemoryPage();
			if(physPage == -1)//Buggy Fixed, -1 is corresponding to Max Unsigned Int, can;t be reached
			{
				printf("FATAL ERROR: Memory not enough to assign new page!!!!\n");
				pageTableLock -> Release();
				return -1;//TO DO MORE
			}

			newPageTable[i].virtualPage = i;
			newPageTable[i].physicalPage = physPage;		 		//Project2:	allocate physical address to virtual page
			newPageTable[i].valid = TRUE;
			newPageTable[i].use = FALSE;
			newPageTable[i].dirty = FALSE;
			newPageTable[i].readOnly = FALSE;					//Stack segment, must be writable 

			DEBUG('2',"Allocating - Virtual P#%03d Addr: 0x%06x Physical P#%03d Addr 0x%06x size %u \n", i, i*PageSize, physPage, physPage*PageSize, PageSize);
			bzero( machine->mainMemory+physPage*PageSize, PageSize);											
		}
		
		//Replace out-of-time varibles
		numPages = numPages + AddPageNum;
		pageTable = newPageTable;
		
		RestoreState();									//Important!!! Restore machine state before deleting old table
		userStackNum = userStackNum + AddStackNum;

		delete oldPageTable;								//delete abandoned space
	}
	
	pageTableLock -> Release();
	return StackId;

#else		//With TLB, project3 Added

	//-----------------Project3-------------------
	int StackId;
	pageTableLock -> Acquire();	//Still used to protect StackId
	
	//Step1: Allocate Stack
	//1-1:	Assign StackId
	StackId = nextStackId;
	nextStackId ++;

	DEBUG('2',"Allocate New Stack Id [%d] \n", StackId);	

	//1-2: If Memory isn't enough, ask OS for more
	if(StackId == userStackNum)	
	{	
		int AddStackNum = userStackNum;	//Every time reach stack bound, double current stacks num
		int AddPageNum = AddStackNum * NumStackPages;
	
		DEBUG('2',"Memory Not Enough, Allocating new Memory, Num Pages [%d] Size [%d] \n", AddPageNum, AddPageNum * PageSize);	
	
		OnDemandTranslationEntry * newPageTable = new OnDemandTranslationEntry[numPages+AddPageNum];
		OnDemandTranslationEntry * oldPageTable = pageTable;
	
		for(int i=0; i<numPages; i++)		//Copy old memory page translation entries
		{
			newPageTable[i] = oldPageTable[i];
			//printf("%d\n",newPageTable[i].virtualPage);
		}
		
		for(int i=numPages;i<numPages+AddPageNum;i++)//Allocate new memory pages
		{
			newPageTable[i].virtualPage = i;
			newPageTable[i].valid = false;										//Project3: every page is invalid at very beginning
			newPageTable[i].use = false;
			newPageTable[i].dirty = false;
			newPageTable[i].readOnly = false;
			newPageTable[i].inDisk = false;										//Project3: if this page is in disk
			newPageTable[i].posId = -1;
		}
		//Replace out-of-time varibles
		numPages = numPages + AddPageNum;
		userStackNum = userStackNum + AddStackNum;
		pageTable = newPageTable;
		delete oldPageTable;								//delete abandoned space
	}

	pageTableLock -> Release();
	return StackId;

#endif
}

//Assumption: Do nothing if error occured;
//Using:
//		pageTable
//		RootStackPage
void AddrSpace::RecycleStackId(int StackId)
{
	pageTableLock -> Acquire();

	DEBUG('2',"Try to Recycle Pages allocated to Stack#[%d] \n", StackId);
	
	if(StackId<0 || StackId >= nextStackId)
	{
		printf("ERROR : Invalid Stack Id [%d] to recycle\n", StackId);
		return;
	}
	
	//For All Used Pages by this Stack Id
	int pageNumber = RootStackPage + StackId  * NumStackPages ;				//the first Virtual Page # allocated to that Stack
	for(int i=0;i<NumStackPages;i++)
	{
		int virtualPageNumber = pageNumber + i;

	//Step0: Skip invalid pages 		
		if(!pageTable[virtualPageNumber].valid)
			continue;
#ifdef USE_TLB
	//Project3
	//recycle IPT entry
		recycleIPT(virtualPageNumber);
	//give up space in swap file
		if(pageTable[virtualPageNumber].inDisk)
			giveupSwap(pageTable[virtualPageNumber].posId);
#endif
	//Step1: Recycle Physical Memory Page
		RecycleMemoryPage(pageTable[virtualPageNumber].physicalPage);
	//Step2: Mark these translations INVALID
		pageTable[virtualPageNumber].valid = FALSE;
	}

	DEBUG('2',"Recycle Pages allocated to Stack#[%d] FINISH.\n", StackId);

	pageTableLock -> Release();
}

//Description: return Stack base virtual addr to a Stack Id
unsigned int AddrSpace::GetStackVaddr(int StackId)
{
	if( StackId<0 || StackId >= nextStackId )
	{
		printf("ERROR : Invalid Stack Id [%d] \n", StackId);
		return InvalidFlag;
	}

	unsigned int addr = (RootStackPage + StackId  * NumStackPages + NumStackPages ) * PageSize - 16;
	// Explanation:		(	StackRoot  +   Pages of Former stacks  + my stack page )->count size, reserve safety zone

	DEBUG('2',"Virtual Addr allocated to Stack ID [%d] starts at Page#%03d Addr 0x%06x \n", StackId, RootStackPage + StackId  * NumStackPages + NumStackPages - 1 , addr);
	return addr;
}

/*
TranslationEntry * AddrSpace::GetVirtualPage(int vpn)
{
	if(vpn <0 || vpn >= numPages)
	{
		printf("ERROR : Requesting Virtual Page Translation Entry with Illeagal VPN %d. numPages=%-5d processId=%-2d\n", vpn, numPages, currentThread->processId);
		return NULL;
	}
#ifndef USE_TLB
	if(!pageTable[vpn].valid)
	{
		printf("ERROR : Requesting Virtual Page %d is INVALID.\n", vpn);
		return NULL;
	}
	return &pageTable[vpn];
#else	//Project3
	TranslationEntry * entry = (TranslationEntry *)queryIPT(vpn);

	if(!entry->valid)
	{
		printf("ERROR : Requesting Virtual Page %d is INVALID.\n", vpn);
		return NULL;
	}
	return entry;
#endif	//USE_TLB
}
*/
unsigned int AddrSpace::GetNumPages()
{
	return numPages;
}

unsigned int AddrSpace::GetCodeSize()
{
	return codeSize;
}

//----------------------------------------------------------------------
//	Add end
//----------------------------------------------------------------------

//----------------------------------------------------------------------
// AddrSpace::~AddrSpace
//
// 	Dealloate an address space.  release pages, page tables, files
// 	and file tables
//----------------------------------------------------------------------
AddrSpace::~AddrSpace()
{
	IntStatus oldLevel = interrupt -> SetLevel(IntOff);
	
	delete pageTableLock;	//OceanMaster
//-------------Project2-----------------	
   //DEBUG('2',"Try to Recycle Memory pages allocated to process %d\n", currentThread->processId); 
   for(int i=0;i<numPages;i++)	//Recycle all physical memory
		if(pageTable[i].valid)
		{
#ifdef USE_TLB		
		//------Project3------
	    	recycleIPT(i);
			//give up space in swap file
			if(pageTable[i].inDisk)
				giveupSwap(pageTable[i].posId);
		//--------end---------
#endif
			RecycleMemoryPage(pageTable[i].physicalPage);
			pageTable[i].valid = false;
		}
//---------------end--------------------
	//DEBUG('2',"Recycle Memory pages allocated to process %d Finish\n", currentThread->processId); 
  
    delete pageTable;
	
	//DEBUG('2',"PageTable Deleted\n"); 
  
#ifdef USE_TLB
	delete myExecutable;
	//DEBUG('2',"Executable File Deleted\n"); 
#endif
//TODO !!!!
	//Add release swap file code.

	interrupt -> SetLevel(oldLevel);
}

//----------------------------------------------------------------------
// AddrSpace::InitRegisters
// 	Set the initial values for the user-level register set.
//
// 	We write these directly into the "machine" registers, so
//	that we can immediately jump to user code.  Note that these
//	will be saved/restored into the currentThread->userRegisters
//	when this thread is context switched out.
//----------------------------------------------------------------------

void
AddrSpace::InitRegisters()
{
    int i;

    for (i = 0; i < NumTotalRegs; i++)
	machine->WriteRegister(i, 0);

    // Initial program counter -- must be location of "Start"
    machine->WriteRegister(PCReg, 0);	

    // Need to also tell MIPS where next instruction is, because
    // of branch delay possibility
    machine->WriteRegister(NextPCReg, 4);

	// Set the stack register to the end of the address space, where we
	// allocated the stack; but subtract off a bit, to make sure we don't
	// accidentally reference off the end!
    
    //machine->WriteRegister(StackReg, numPages * PageSize - 16);
    machine->WriteRegister(StackReg, (RootStackPage + 1 * NumStackPages) * PageSize - 16);

	//OceanMaster: Changed!!!!!!!!
    DEBUG('a', "Initializing stack register to %x\n", numPages * PageSize - 16);
}

//----------------------------------------------------------------------
// AddrSpace::SaveState
// 	On a context switch, save any machine state, specific
//	to this address space, that needs saving.
//
//	For now, nothing!
//----------------------------------------------------------------------

//OceanMaster: 
//This is called before context switch
void AddrSpace::SaveState() 
{
	//printf("AddreSpace SaveState\n");
}

//----------------------------------------------------------------------
// AddrSpace::RestoreState
// 	On a context switch, restore the machine state so that
//	this address space can run.
//
//      For now, tell the machine where to find the page table.
//----------------------------------------------------------------------

//Oceanmaster: To be added
void AddrSpace::RestoreState() 
{
//------------------Project 3------------------------
//Modifying:
//Added pre-compile command to prevent this when USE_TLB
	DEBUG('$',"Context switch\n");
#ifdef USE_TLB
    //DEBUG('3',"Using TLB, Clear TLB table before context switch.\n");
	TLBCleanUp();
#else
    //DEBUG('3',"Not using TLB, Restore Page Table\n");
    machine->pageTable = pageTable;
    machine->pageTableSize = numPages;
#endif
//------------------End modify-----------------------
}
